﻿<!DOCTYPE html>
<html>
<head>
    <title>JS Strings Exercise 4</title>
    <link href="styles/js-console.css" rel="stylesheet" />
</head>
<body>
    <h1>Function that changes the text in all regions.</h1>
    <label for="str-input">String:</label>
    <input type="text" id="str-input" />
    <button onclick="execute()">execute</button>
    <div id="js-console"></div>
    <script src="scripts/js-console.js"></script>
    <script>
        // Add toRandomCase() function is all strings that will change every char randomly
        String.prototype.toRandomCase = function()
        {
            var strLen = this.length;
            var retStr = "";
            for (var idx = 0; idx < strLen; idx++)
            {
                if (Math.random() > 0.5)
                {
                    retStr += this.charAt(idx).toLowerCase();
                }
                else
                {
                    retStr += this.charAt(idx).toUpperCase();
                }
            }

            return retStr;
        }

        // Tag type enumeration
        var tagNoTag = 0;
        var tagOpenLow = 1;
        var tagOpenUp = 2;
        var tagOpenMix = 3;
        var tagCloseLow = 4;
        var tagCloseUp = 5;
        var tagCloseMix = 6;

        // Get next tag. Return its type, start and end position in an object
        function getNextTag(text, start)
        {
            var openIdx = text.indexOf("<", start);
            var closeIdx = text.indexOf(">", start);
            var tagType = tagNoTag;

            if ((openIdx >= 0) && (closeIdx > 0))
            {
                var tagName = text.substring(openIdx, closeIdx + 1);
                if (tagName == "<upcase>")
                {
                    tagType = tagOpenUp;
                }
                else if (tagName == "<lowcase>")
                {
                    tagType = tagOpenLow;
                }
                else if (tagName == "<mixcase>")
                {
                    tagType = tagOpenMix;
                }
                else if (tagName == "</upcase>")
                {
                    tagType = tagCloseUp;
                }
                else if (tagName == "</lowcase>")
                {
                    tagType = tagCloseLow;
                }
                else if (tagName == "</mixcase>")
                {
                    tagType = tagCloseMix;
                }
            }

            return {
                tagType: tagType,
                tagStartIdx: openIdx,
                tagEndIdx: closeIdx
            }
        }

        // Format type enumeration
        var formatNoChange = 0;
        var formatUpper = 1;
        var formatLower = 2;
        var formatMixed = 3;

        // Format string according its type and return it.
        function formatString(str, type)
        {
            if (formatUpper == type)
            {
                str = str.toUpperCase();
            }
            else if (formatLower == type)
            {
                str = str.toLowerCase();
            }
            else if (formatMixed == type)
            {
                str = str.toRandomCase();
            }

            return str;
        }

        // Main format function
        function formatRegions(text)
        {
            var strRes = "";
            var formatStack = [];
            var currTag;
            var currStart = 0;
            var currFinish = 0;

            // Stack is used to store nested formats
            // Text start with no format.
            // With every open tag we push new format in this stack.
            // With every close tag we pop format from this stack.
            // We process according to top format type.
            formatStack.push(formatNoChange);
            
            do
            {
                var processText;

                currTag = getNextTag(text, currStart);

                // format text between to tags
                if (currTag.tagType != tagNoTag)
                {
                    currFinish = currTag.tagStartIdx;
                }
                else
                {
                    currFinish = text.length;
                }
                processText = text.substring(currStart, currFinish);
                processText = formatString(processText, formatStack[formatStack.length - 1]);

                // Add formatted string to final result string
                strRes += processText;

                // Process format stack
                switch (currTag.tagType)
                {
                    case tagOpenLow:
                        formatStack.push(formatLower);
                        break;
                    case tagOpenUp:
                        formatStack.push(formatUpper);
                        break;
                    case tagOpenMix:
                        formatStack.push(formatMixed);
                        break;
                    case tagCloseLow:
                        if (formatStack[formatStack.length - 1] == formatLower)
                        {
                            formatStack.pop();
                        }
                        break;
                    case tagCloseUp:
                        if (formatStack[formatStack.length - 1] == formatUpper)
                        {
                            formatStack.pop();
                        }
                        break;
                    case tagCloseMix:
                        if (formatStack[formatStack.length - 1] == formatMixed)
                        {
                            formatStack.pop();
                        }
                        break;
                }

                // Calculate start position for the rest of the text to be processed
                currStart = currTag.tagEndIdx + 1;
                
                // Repeat until there is more tags to process
            } while (currTag.tagType > tagNoTag);

            return strRes;
        }

        function execute()
        {
            var inpStr = jsConsole.read("#str-input");
                        
            jsConsole.writeLine(formatRegions(inpStr));
        }
    </script>
</body>
</html>
